﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Net.Sockets;
using System.IO.Ports;
using Modbus.Device;

namespace MotionCS.Controller
{
    public class Dm2cApi
    {
        /// <summary>
        /// 单例锁对象
        /// </summary>
        private static object _objLock = new object();
        /// <summary>
        /// 单例对象
        /// </summary>
        private static Dm2cApi _instance;
        /// <summary>
        /// 单例对象
        /// </summary>
        public static Dm2cApi Instance
        {
            get
            {
                if ( _instance == null )
                {
                    lock( _objLock )
                    {
                        if (_instance == null)
                        {
                            _instance = new Dm2cApi();
                        }
                    }
                }

                return _instance;
            }
        }
        /// <summary>
        /// 日志回调
        /// </summary>
        public Action<string> LogoutCallback { get; set; }
        /// <summary>
        /// modbus主端
        /// </summary>
        private IModbusMaster modbusMaster;
        /// <summary>
        /// 串口端口
        /// </summary>
        private SerialPort serialPort;
        /// <summary>
        /// TCP客户端
        /// </summary>
        private TcpClient tcpMaster;
        /// <summary>
        /// 打开Modbus Rtu
        /// </summary>
        /// <param name="portName"></param>
        /// <param name="baudRate"></param>
        public void RtuOpen(string portName, int baudRate)
        {
            try
            {
                serialPort = new SerialPort(portName);
                serialPort.BaudRate = baudRate;
                serialPort.DataBits = 8;
                serialPort.Parity = Parity.None;
                serialPort.StopBits = StopBits.One;
                serialPort.Open();

                if (serialPort.IsOpen)
                {
                    modbusMaster = ModbusSerialMaster.CreateRtu(serialPort);
                    modbusMaster.Transport.ReadTimeout = 200;                   
                }
            }
            catch (Exception ex)
            {
                
            }
        }
        /// <summary>
        /// 关闭Modbus Rtu
        /// </summary>
        public void RtuClose()
        {
            if (modbusMaster != null)
            {
                modbusMaster?.Dispose();
                modbusMaster = null;
            }
            if (serialPort != null)
            {
                serialPort?.Dispose();
                serialPort?.Close();
                serialPort = null;
            }
        }

        /// <summary>
        /// 打开Modbus Tcp
        /// </summary>
        /// <param name="ip"></param>
        /// <param name="port"></param>
        public void TcpOpen(string ip, int port)
        {
            try
            {
                tcpMaster = new TcpClient();
                IAsyncResult result = tcpMaster.BeginConnect(ip, port, AsyncCallback, tcpMaster); 
            }
            catch (Exception ex)
            {
               
            }
        }
        /// <summary>
        /// socket连接异步回调
        /// </summary>
        /// <param name="ar"></param>
        private void AsyncCallback(IAsyncResult ar)
        {
            TcpClient cli = (TcpClient)ar.AsyncState;

            if (cli.Connected)
            {
                modbusMaster = ModbusIpMaster.CreateIp(tcpMaster);

                modbusMaster.Transport.ReadTimeout = 200;
                modbusMaster.Transport.WriteTimeout = 200;
            }
        }
        /// <summary>
        /// 关闭Modbus Tcp
        /// </summary>
        public void TcpClose()
        {
            if (modbusMaster != null)
            {
                modbusMaster?.Dispose();
                modbusMaster = null;
            }
            if (modbusMaster != null)
            {
                tcpMaster?.Close();
                tcpMaster?.Dispose();
                tcpMaster = null;
            }
        }
        /// <summary>
        /// modbus是否打开
        /// </summary>
        /// <returns></returns>
        public bool IsOpen()
        {
            return modbusMaster != null;
        }
        /// <summary>
        /// ushort转float
        /// </summary>
        /// <param name="high"></param>
        /// <param name="low"></param>
        /// <returns></returns>
        public float ToFloat(ushort high, ushort low)
        {
            return BitConverter.ToSingle(BitConverter.GetBytes(high << 16 | low), 0);
        }
        /// <summary>
        /// ushort转uint
        /// </summary>
        /// <param name="high"></param>
        /// <param name="low"></param>
        /// <returns></returns>
        public UInt32 ToUInt32(ushort high, ushort low)
        {
            return BitConverter.ToUInt32(BitConverter.GetBytes(high << 16 | low), 0);
        }
        /// <summary>
        /// ushort转int
        /// </summary>
        /// <param name="high"></param>
        /// <param name="low"></param>
        /// <returns></returns>
        public Int32 ToInt32(ushort high, ushort low)
        {
            return BitConverter.ToInt32(BitConverter.GetBytes(high << 16 | low), 0);
        }
        /// <summary>
        /// 日志输出
        /// </summary>
        /// <param name="loginfo"></param>
        private void Logout(string loginfo)
        {
            LogoutCallback?.Invoke(loginfo);
        }
        /// <summary>
        /// int32转ushort
        /// </summary>
        /// <param name="i32"></param>
        /// <returns></returns>
        private ushort[] GetUInt16(Int32 value)
        {
            byte[] bytes = BitConverter.GetBytes(value);
            ushort low = BitConverter.ToUInt16(bytes, 0);
            ushort high = BitConverter.ToUInt16(bytes, 2);

            return new ushort[] { low, high };
        }

        /// <summary>
        /// uint转ushort
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        private ushort[] GetUInt16(UInt32 value)
        {
            byte[] bytes = BitConverter.GetBytes(value);
            ushort low = BitConverter.ToUInt16(bytes, 0);
            ushort high = BitConverter.ToUInt16(bytes, 2);

            return new ushort[] { low, high };
        }
        /// <summary>
        /// float转ushort
        /// </summary>
        /// <param name="f"></param>
        /// <returns></returns>
        private ushort[] GetUInt16(float value)
        {
            byte[] bytes = BitConverter.GetBytes(value);

            ushort low = BitConverter.ToUInt16(bytes, 0);
            ushort high = BitConverter.ToUInt16(bytes, 2);

            return new ushort[] { low, high };
        }
        /// <summary>
        /// 驱动器使能
        /// </summary>
        /// <param name="addr"></param>
        /// <returns></returns>
        public int DriverEnable(byte addr)
        {
            try
            {
                modbusMaster?.WriteSingleRegister(addr, 0x00F, 1);
                Logout($"节点{addr}驱动器软件使能.");
                return 0;
            }
            catch (Exception ex)
            {
                return -1;
            }
        }
        /// <summary>
        /// 峰值电流
        /// </summary>
        /// <param name="addr"></param>
        /// <param name="current"></param>
        /// <returns></returns>
        public int PeakCurrent(byte addr, ushort current)
        {
            try
            {
                modbusMaster?.WriteSingleRegister(addr, 0x191, current);
                Logout($"节点{addr}驱动器设置峰值电流{current}.");
                return 0;
            }
            catch (Exception ex)
            {
                return -1;
            }
        }
        /// <summary>
        /// 正向JOG输入2
        /// </summary>
        /// <param name="addr"></param>
        /// <returns></returns>
        public int ForwardJogInput2(byte addr)
        {
            try
            {
                modbusMaster?.WriteSingleRegister(addr, 0x147, 0x23);
                Logout($"节点{addr}驱动器设置正向JOG输入2.");
                return 0;
            }
            catch (Exception ex)
            {
                return -1;
            }
        }
        /// <summary>
        /// 正向JOG输入3
        /// </summary>
        /// <param name="addr"></param>
        /// <returns></returns>
        public int ForwardJogInput3(byte addr)
        {
            try
            {
                modbusMaster?.WriteSingleRegister(addr, 0x149, 0x23);
                Logout($"节点{addr}驱动器设置正向JOG输入3.");
                return 0;
            }
            catch (Exception ex)
            {
                return -1;
            }
        }
        /// <summary>
        /// 反向JOG输入2
        /// </summary>
        /// <param name="addr"></param>
        /// <returns></returns>
        public int BackwardJogInput2(byte addr)
        {
            try
            {
                modbusMaster?.WriteSingleRegister(addr, 0x147, 0x24);
                Logout($"节点{addr}驱动器设置反向JOG输入2.");
                return 0;
            }
            catch (Exception ex)
            {
                return -1;
            }
        }
        /// <summary>
        /// 反向JOG输入3
        /// </summary>
        /// <param name="addr"></param>
        /// <returns></returns>
        public int BackwardJogInput3(byte addr)
        {
            try
            {
                modbusMaster?.WriteSingleRegister(addr, 0x149, 0x24);
                Logout($"节点{addr}驱动器设置反向JOG输入3.");
                return 0;
            }
            catch (Exception ex)
            {
                return -1;
            }
        }
        /// <summary>
        /// 报警输出
        /// </summary>
        /// <param name="addr"></param>
        /// <returns></returns>
        public int AlarmOutput(byte addr)
        {
            try
            {
                modbusMaster?.WriteSingleRegister(addr, 0x157, 0x105);
                Logout($"节点{addr}驱动器设置报警输出.");
                return 0;
            }
            catch (Exception ex)
            {
                return -1;
            }
        }

        /// <summary>
        /// 设置急停减速时间
        /// </summary>
        /// <param name="addr">节点地址</param>
        /// <param name="speed">速度(r/min)</param>
        /// <returns></returns>
        public int SetEmgTime(byte addr, ushort time)
        {
            try
            {
                modbusMaster?.WriteSingleRegister(addr, 0x6017, time);
                Logout($"节点{addr}驱动器设置急停减速时间{time}.");
                return 0;
            }
            catch (Exception ex)
            {
                return -1;
            }
        }
        /// <summary>
        /// 获取JOG运行速度
        /// </summary>
        /// <param name="addr"></param>
        /// <returns></returns>
        public ushort GetEmgTime(byte addr)
        {
            try
            {
                ushort[] val = modbusMaster?.ReadHoldingRegisters(addr, 0x6017, 1);

                return val[0];
            }
            catch (Exception ex)
            {
                return 0;
            }
        }
        /// <summary>
        /// 设置JOG运行速度
        /// </summary>
        /// <param name="addr">节点地址</param>
        /// <param name="speed">速度(r/min)</param>
        /// <returns></returns>
        public int SetSpeed(byte addr, ushort speed)
        {
            try
            {
                modbusMaster?.WriteSingleRegister(addr, 0x6027, speed);
                Logout($"节点{addr}驱动器设置JOG速度{speed}.");
                return 0;
            }
            catch (Exception ex)
            {
                return -1;
            }
        }
        /// <summary>
        /// 获取JOG运行速度
        /// </summary>
        /// <param name="addr"></param>
        /// <returns></returns>
        public ushort GetSpeed(byte addr)
        {
            try
            {
                ushort[] val = modbusMaster?.ReadHoldingRegisters(addr, 0x6027, 1);

                return val[0];
            }
            catch (Exception ex)
            {
                return 0;
            }
        }

        /// <summary>
        /// 设置JOG加速度
        /// </summary>
        /// <param name="addr">节点地址</param>
        /// <param name="accel">速度(r/min)</param>
        /// <returns></returns>
        public int SetAccel(byte addr, ushort accel)
        {
            try
            {
                modbusMaster?.WriteSingleRegister(addr, 0x6028, accel);
                Logout($"节点{addr}驱动器设置JOG加速度{accel}.");
                return 0;
            }
            catch (Exception ex)
            {
                return -1;
            }
        }
        /// <summary>
        /// 获取JOG加速度
        /// </summary>
        /// <param name="addr"></param>
        /// <returns></returns>
        public ushort GetAccel(byte addr)
        {
            try
            {
                ushort[] val = modbusMaster?.ReadHoldingRegisters(addr, 0x6028, 1);

                return val[0];
            }
            catch (Exception ex)
            {
                return 0;
            }
        }

        /// <summary>
        /// 设置JOG减速度
        /// </summary>
        /// <param name="addr">节点地址</param>
        /// <param name="accel">速度(r/min)</param>
        /// <returns></returns>
        public int SetDecel(byte addr, ushort decel)
        {
            try
            {
                modbusMaster?.WriteSingleRegister(addr, 0x6029, decel);
                Logout($"节点{addr}驱动器设置JOG减速度{decel}.");
                return 0;
            }
            catch (Exception ex)
            {
                return -1;
            }
        }
        /// <summary>
        /// 获取JOG减速度
        /// </summary>
        /// <param name="addr"></param>
        /// <returns></returns>
        public ushort GetDecel(byte addr)
        {
            try
            {
                ushort[] val = modbusMaster?.ReadHoldingRegisters(addr, 0x6029, 1);

                return val[0];
            }
            catch (Exception ex)
            {
                return 0;
            }
        }
        /// <summary>
        /// 读取报警码
        /// </summary>
        /// <param name="addr"></param>
        /// <returns></returns>
        public ushort GetAlarm(byte addr)
        {
            try
            {
                ushort[] val = modbusMaster?.ReadHoldingRegisters(addr, 0x2203, 1);
                Logout($"节点{addr}驱动器读取报警码{val[0]}.");
                return val[0];
            }
            catch (Exception ex)
            {
                return 0;
            }
        }
        /// <summary>
        /// 保存参数
        /// </summary>
        /// <param name="addr"></param>
        /// <returns></returns>
        public int SaveParam(byte addr)
        {
            try
            {
                modbusMaster?.WriteSingleRegister(addr, 0x1801, 0x2211);
                Logout($"节点{addr}驱动器保存参数.");
                return 0;
            }
            catch (Exception ex)
            {
                return -1;
            }
        }
        /// <summary>
        /// 恢复默认参数
        /// </summary>
        /// <param name="addr"></param>
        /// <returns></returns>
        public int DefaultParam(byte addr)
        {
            try
            {
                modbusMaster?.WriteSingleRegister(addr, 0x1801, 0x2233);
                return 0;
            }
            catch (Exception ex)
            {
                return -1;
            }
        }
        /// <summary>
        /// 复位当前报警
        /// </summary>
        /// <param name="addr"></param>
        /// <returns></returns>
        public int ResetCurrentAlarm(byte addr)
        {
            try
            {
                modbusMaster?.WriteSingleRegister(addr, 0x1801, 0x1111);
                return 0;
            }
            catch (Exception ex)
            {
                return -1;
            }
        }
        /// <summary>
        /// 复位历史报警
        /// </summary>
        /// <param name="addr"></param>
        /// <returns></returns>
        public int ResetHistoryAlarm(byte addr)
        {
            try
            {
                modbusMaster?.WriteSingleRegister(addr, 0x1801, 0x1122);
                return 0;
            }
            catch (Exception ex)
            {
                return -1;
            }
        }
    }
}
